package com.legsem.jhosync.change;

import com.legsem.jhosync.model.ClientDoc;
import com.legsem.jhosync.model.MasterDoc;
import com.legsem.jhosync.util.KAVUtil;

/**
 * Gathers changes that need to be applied to documents or fed back to client.
 * <p/>
 * Changes are organized in the following fields:
 * <ul>
 * <li>inserts: successfully created entities</li>
 * <li>deletes: successfully deleted entities</li>
 * <li>create_links: the linking hash to return new identifiers following create
 * operations</li>
 * <li>create_deletes: unsuccessful creates that need to be removed from client</li>
 * <li>operation_errors: used to report source exceptions that were caught.
 * Errors are related to the client requested operation.</li>
 * <li>metadata: metadata that needs to be sent back to client</li>
 * </ul>
 */
public class ChangesSet {

    private Inserts inserts = new Inserts();
    private Deletes deletes = new Deletes();
    private CreateLinks createLinks = new CreateLinks();
    private CreateDeletes createDeletes = new CreateDeletes();
    private CreateErrors createErrors = new CreateErrors();
    private UpdateErrors updateErrors = new UpdateErrors();
    private DeleteErrors deleteErrors = new DeleteErrors();
    private SourceErrors sourceErrors = new SourceErrors();
    private String metadata;
    private String metadataSha1;

    public ChangesSet() {

    }

    /**
     * Create a changes set by comparing the master document with the client
     * document.
     * <p/>
     * Starts by evaluating the differences between the documents contents.
     * <p/>
     * Compare the metadata and if there are changes stores the new version in
     * the change set.
     * 
     * @param masterDoc the master document object
     * @param clientDoc the client document object
     */
    public ChangesSet(MasterDoc masterDoc, ClientDoc clientDoc) {

        KAVUtil.sdiff(masterDoc.getMd(), clientDoc.getCd(), inserts, deletes);

        if (clientDoc.getMetadataSha1() == null) {
            if (masterDoc.getMetadataSha1() == null) {
                return;
            }
        } else {
            if (clientDoc.getMetadataSha1().equals(masterDoc.getMetadataSha1())) {
                return;
            }
        }
        metadata = masterDoc.getMetadata();
        metadataSha1 = masterDoc.getMetadataSha1();
    }

    /**
     * Apply changes from this changes set to a KAV encoded set and return the
     * KAV encoded result.
     * 
     * @param set the key/attribute/value encoded set
     * @return the updated key/attribute/value encoded set
     */
    public String apply(String set) {
        return KAVUtil.apply(this, set);
    }

    /**
     * Deletes reduce the row count while creates increase it.
     * 
     * @return how this change set affects row count.
     */
    public int updateCount() {
        return inserts.size() - deletes.size();
    }

    public Inserts getInserts() {
        return inserts;
    }

    public void setInserts(Inserts inserts) {
        this.inserts = inserts;
    }

    public Deletes getDeletes() {
        return deletes;
    }

    public void setDeletes(Deletes deletes) {
        this.deletes = deletes;
    }

    public CreateLinks getCreateLinks() {
        return createLinks;
    }

    public void setCreateLinks(CreateLinks createLinks) {
        this.createLinks = createLinks;
    }

    public CreateDeletes getCreateDeletes() {
        return createDeletes;
    }

    public void setCreateDeletes(CreateDeletes createDeletes) {
        this.createDeletes = createDeletes;
    }

    public CreateErrors getCreateErrors() {
        return createErrors;
    }

    public void setCreateErrors(CreateErrors createErrors) {
        this.createErrors = createErrors;
    }

    public UpdateErrors getUpdateErrors() {
        return updateErrors;
    }

    public void setUpdateErrors(UpdateErrors updateErrors) {
        this.updateErrors = updateErrors;
    }

    public DeleteErrors getDeleteErrors() {
        return deleteErrors;
    }

    public void setDeleteErrors(DeleteErrors deleteErrors) {
        this.deleteErrors = deleteErrors;
    }

    public SourceErrors getSourceErrors() {
        return sourceErrors;
    }

    public void setSourceErrors(SourceErrors sourceErrors) {
        this.sourceErrors = sourceErrors;
    }

    public String getMetadata() {
        return metadata;
    }

    public void setMetadata(String metadata) {
        this.metadata = metadata;
    }

    public String getMetadataSha1() {
        return metadataSha1;
    }

    public void setMetadataSha1(String metadataSha1) {
        this.metadataSha1 = metadataSha1;
    }

    @Override
    public String toString() {
        return "ChangesSet [inserts=" + inserts + ", deletes=" + deletes
                + ", createLinks=" + createLinks + ", createDeletes="
                + createDeletes + ", createErrors=" + createErrors
                + ", updateErrors=" + updateErrors + ", deleteErrors="
                + deleteErrors + ", sourceErrors=" + sourceErrors
                + ", metadata=" + metadata + ", metadataSha1=" + metadataSha1
                + "]";
    }

}
